package com.dingwen.stumybplu.controller;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dingwen.stumybplu.constant.Tip;
import com.dingwen.stumybplu.entity.User;
import com.dingwen.stumybplu.exception.ServiceException;
import com.dingwen.stumybplu.result.Result;
import com.dingwen.stumybplu.result.ResultGenerator;
import com.dingwen.stumybplu.service.IUserService;
import com.dingwen.stumybplu.service.impl.UserServiceImpl;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import jdk.nashorn.internal.objects.annotations.Getter;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.jws.soap.SOAPBinding;
import java.sql.Wrapper;
import java.util.*;
import java.util.function.Consumer;

/**
 * <p>
 * 系统用户表 前端控制器
 * </p>
 *
 * @author dingwen
 * @since 2021-06-07
 */
@RestController
@RequestMapping("/user")
public class UserController {

    private static final String COLUMN_TIP = "列清单不能为空";
    /**
     * 用户服务
     */
    private final IUserService userService;

    public UserController(IUserService userService) {
        this.userService = userService;
    }

    /**
     * 查询用户列表
     *
     * @return {@link Result}
     */
    @ApiOperation("查询用户列表")
    @GetMapping("/list")
    public Result get() {
        List<User> userList = userService.list();
        return ResultGenerator.genOkResult(userList);
    }


    /**
     * selectMaps:将查询结果封装为一个 Map，Map 的 key 为结果的列，value 为值
     * 使用场景：当某个表的列特别多，而 SELECT 的时候只需要选取个别列，查询出的结果也没必要封装成 Java 实体类对象时
     * （只查部分列时，封装成实体后，实体对象中的很多属性会是 null），则可以用selectMaps，获取到指定的列后，再自行进
     * 行处理即可
     *
     * @param columnNameListStr 列清单
     * @return {@link Result}
     */
    @ApiOperation("查询部分列测试")
    @ApiImplicitParam(
            value = "列清单",
            name = "columnNameListStr   "
    )
    @GetMapping("map/part")
    public Result getMapsColumn(@RequestParam String columnNameListStr) {
        QueryWrapper<User> userQueryWrapper = columnNameListStrHandle(columnNameListStr);
        List<Map<String, Object>> listMaps = userService.listMaps(userQueryWrapper);
        return ResultGenerator.genOkResult(listMaps);
    }


    /**
     * 按照直属上级进行分组，查询每组的平均年龄，最大年龄，最小年龄,最后帅选合计年龄大于30的用户
     *
     * @return {@link Result}
     */
    @ApiOperation("年龄统计")
    @GetMapping("/map/statistics")
    public Result getMapsStatistics() {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.select("manager_id", "name", "avg(age) avg_age", "sum(age) avg_sum", "min(age) avg_age", "max(age) avg_age")
                .groupBy("manager_id", "name")
                .having("sum(age) > {0}", 30);
        List<Map<String, Object>> listMaps = userService.listMaps(userQueryWrapper);
        return ResultGenerator.genOkResult(listMaps);
    }

    /**
     * 只会返回第一个字段（第一列）的值，其他字段会被舍弃
     *
     * @return {@link Result}
     */
    @ApiOperation("查询ID")
    @GetMapping("/objs")
    public Result getObjs() {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<User>().select("id", "name");
        List<Object> objectList = userService.listObjs(userQueryWrapper);
        return ResultGenerator.genOkResult(objectList);
    }

    /**
     * 根据条件查询记录数
     *
     * @return {@link Result}
     */
    @ApiOperation("根据条件查询记录数")
    @GetMapping("/count")
    public Result getCount() {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<User>().like("name", "黄");
        Integer count = userService.count(userQueryWrapper);
        return ResultGenerator.genOkResult(count);
    }

    /**
     * 得到一个
     *
     * @return {@link Result}
     */
    @GetMapping("/one")
    @ApiOperation("查询一个用户")
    public Result getOne() {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = Wrappers.<User>lambdaQuery().gt(User::getAge, 24);
        // 及时查到多条记录也不报错，返回第一条数据
        User user = userService.getOne(userLambdaQueryWrapper, false);
        return ResultGenerator.genOkResult(user);
    }

    /**
     * 条件查询测试
     *
     * @return {@link Result}
     */
    @GetMapping("/select")
    @ApiOperation("条件查询测试")
    public Result getSelect() {
        List<User> userList = userService.lambdaQuery()
                .gt(User::getAge, 30)
                .likeRight(User::getName, "黄")
                .list();
        return ResultGenerator.genOkResult(userList);
    }

    /**
     * 更新示例
     *
     * @return {@link Result}
     */
    @ApiOperation("更新示例")
    @PutMapping("/modify")
    public Result modify() {
        boolean flag = userService.lambdaUpdate()
                .ge(User::getName, "小菜")
                .set(User::getName, "dingwen")
                .update();
        return ResultGenerator.genOkResult(flag);
    }

    /**
     * 删除示例
     *
     * @return {@link Result}
     */
    @ApiOperation("删除示例")
    @DeleteMapping("/remove1")
    public Result remove() {
        boolean flag = userService.lambdaUpdate()
                .eq(User::getId, 100)
                .update();
        return ResultGenerator.genOkResult(false);
    }

    /**
     * 自定义SQL传参测试
     *
     * @return {@link Result}
     */
    @GetMapping("/findAll")
    @ApiOperation("自定义SQL传参测试")
    public Result findAll() {
        // 更新类似
        List<User> userList = userService.findAll(new QueryWrapper<User>().lambda().eq(User::getId, 101));
        return ResultGenerator.genOkResult(userList);
    }

    /**
     * 逻辑删除测试：
     * INSERT 语句：没有影响
     * SELECT 语句：追加 WHERE 条件，过滤掉已删除的数据
     * UPDATE 语句：追加 WHERE 条件，防止更新到已删除的数据
     * DELETE 语句：转变为 UPDATE 语句
     * 自定义的SQL不会产生影响
     *
     * @return {@link Result}
     */
    @DeleteMapping("/remove2")
    @ApiOperation("逻辑删除测试")
    public Result logicDelete() {
        boolean flag = userService.removeById(100);
        return ResultGenerator.genOkResult(flag);
    }

    /**
     * 添加测试：
     *  createTime: 自动填充
     *
     * @param user 用户
     * @return {@link Result}
     */
    @ApiOperation("插入自动填充创建时间测试")
    @PostMapping("add")
    public Result add(@RequestBody User user) {
        boolean flag = userService.save(user);
        // 自动填充，当属性有值时使用改值
        return ResultGenerator.genOkResult(flag);
    }

    /**
     * 列名单str处理
     * 目前支持10参数的可变参数
     *
     * @param columnNameListStr 列名单str
     * @return {@link QueryWrapper<User>}
     */
    private QueryWrapper<User> columnNameListStrHandle(String columnNameListStr) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<User>();
        List<String> columnList = Arrays.asList(columnNameListStr.split(","));
        Optional.of(columnList).orElseThrow(() -> new ServiceException(Tip.getTip(1).getDescription()));
        int size = columnList.size();
        switch (size) {
            case 2:
                userQueryWrapper.select(columnList.get(0), columnList.get(1));
                break;
            case 3:
                userQueryWrapper.select(columnList.get(0), columnList.get(1), columnList.get(2));
                break;
            case 4:
                userQueryWrapper.select(columnList.get(0), columnList.get(1), columnList.get(2), columnList.get(3));
                break;
            case 5:
                userQueryWrapper.select(columnList.get(0), columnList.get(1), columnList.get(2), columnList.get(3), columnList.get(4));
                break;
            case 6:
                userQueryWrapper.select(columnList.get(0), columnList.get(1), columnList.get(2), columnList.get(3), columnList.get(4), columnList.get(5));
                break;
            case 7:
                userQueryWrapper.select(columnList.get(0), columnList.get(1), columnList.get(2), columnList.get(3), columnList.get(4), columnList.get(5), columnList.get(6));
                break;
            case 8:
                userQueryWrapper.select(columnList.get(0), columnList.get(1), columnList.get(2), columnList.get(3), columnList.get(4), columnList.get(5), columnList.get(6), columnList.get(7));
                break;
            case 9:
                userQueryWrapper.select(columnList.get(0), columnList.get(1), columnList.get(2), columnList.get(3), columnList.get(4), columnList.get(5), columnList.get(6), columnList.get(7), columnList.get(8));
                break;
            case 10:
                userQueryWrapper.select(columnList.get(0), columnList.get(1), columnList.get(2), columnList.get(3), columnList.get(4), columnList.get(5), columnList.get(6), columnList.get(7), columnList.get(8), columnList.get(9));
                break;
            default:
                userQueryWrapper.select(columnList.get(0));
        }

        return userQueryWrapper;
    }


    private void test() {
        // 1. 名字中包含佳，且年龄小于25 SELECT * FROM user WHERE name like '%佳%' AND age < 25
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<User>().like("name", "佳")
                .lt("age", 30);
        List<User> userList = userService.list(userQueryWrapper);

        // 2. 姓名为黄姓，且年龄大于等于20，小于等于40，且email字段不为空 SELECT * FROM user WHERE name like '黄%' AND age BETWEEN 20 AND 40 AND email is not null
        userQueryWrapper.likeLeft("name", "黄")
                .between("age", 20, 40)
                .isNotNull("email");

        // 3. 姓名为黄姓，或者年龄大于等于40，按照年龄降序排列，年龄相同则按照id升序排列 SELECT * FROM user WHERE name like '黄%' OR age >= 40 order by age desc, id asc
        userQueryWrapper.likeLeft("name", "黄")
                .or()
                .ge("age", 40)
                .orderByDesc("age")
                .orderByAsc("id");

        // 4.创建日期为2021年3月22日，并且直属上级的名字为李姓 SELECT * FROM user date_format(create_time,'%Y-%m-%d') = '2021-03-22' AND manager_id IN (SELECT id FROM user WHERE name like '李%')
        userQueryWrapper.apply("date_format(create_time,'%Y-%m-%d') = {0}", "2021-03-22")
                .inSql("manager_id", "SELECT id FROM user WHERE name like '李%'");


        // 5. 名字为王姓，并且（年龄小于40，或者邮箱不为空）SELECT * FROM user name like '王%' AND (age < 40 OR email is not null)
        userQueryWrapper.likeLeft("name", "王")
                .and(c -> c.lt("age", 40).or().isNotNull("email"));

        // 6. 名字为王姓，或者（年龄小于40并且年龄大于20并且邮箱不为空）SELECT * FROM user name like '王%' OR (age < 40 AND age > 20 AND email is not null)
        userQueryWrapper.likeLeft("name", "王")
                .or(c -> c.between("age", 20, 40).isNotNull("email"));

        // 7. (年龄小于40或者邮箱不为空) 并且名字为王姓 SELECT * FROM user (age < 40 OR email is not null) AND name like '王%'
        userQueryWrapper.nested(c -> c.lt("age", 40).or().isNotNull("email")).likeLeft("name", "王");

        // 8. 年龄为30，31，34，35 SELECT * FROM user age IN (30,31,34,35)
        userQueryWrapper.in("age", Arrays.asList(30, 31, 34, 35));
        userQueryWrapper.inSql("age", "30,31,34,35");

        // 9. 年龄为30，31，34，35, 返回满足条件的第一条记录 SELECT * FROM user age IN (30,31,34,35) LIMIT 1
        userQueryWrapper.in("age", Arrays.asList(30, 31, 34, 35)).last("LIMIT 1");

        // 10. 只选出id, name 列 (QueryWrapper 特有) SELECT id, name FROM user;
        userQueryWrapper.select("id", "name");

        // 11. 选出id, name, age, email, 等同于排除 manager_id 和 create_time
        // 当列特别多, 而只需要排除个别列时, 采用上面的方式可能需要写很多个列, 可以采用重载的select方法，指定需要排除的列
        userQueryWrapper.select(User.class, info -> !"create_time".equals(info.getColumn()) && !"manager_id".equals(info.getColumn()));

        // 12.条件构造器的诸多方法中，均可以指定一个boolean类型的参数condition，用来决定该条件是否加入最后生成的 WHERE 语句中
        String name = "dingwen";
        userQueryWrapper.lambda()
                // 只有当name不为空时才会将条件写入where字句中
                .like(StringUtils.hasText(name), User::getName, name);


        // 13. 调用构造函数创建一个Wrapper对象时，可以传入一个实体对象。
        // 后续使用这个Wrapper时，会以实体对象中的非空属性，构建 WHERE 条件（默认构建等值匹配的 WHERE 条件
        // ，这个行为可以通过实体类里各个字段上的@TableField注解中的condition属性进行改变）

        User user = User.builder().name("dingwen").age(24).build();
        QueryWrapper<User> wrapper = new QueryWrapper<>(user);

        // name age非空
        // 结果： where name = 'dingwen' and age = 24
        // 根据实体对象中的非空属性，进行了等值匹配查询


        // 14.allEq 方法传入一个map，用来做等值匹配
        QueryWrapper<Object> queryWrapper = new QueryWrapper<>();
        HashMap<String, Object> params = new HashMap<>(3);
        params.put("name", "dingwen");
        params.put("age", 24);
        // where grander_id = null
        params.put("grander_id", null);
//        queryWrapper.allEq(params);
        // 可以进行过滤
        // 过滤掉value is null 的数据
        queryWrapper.allEq((k, v) -> !ObjectUtils.isEmpty(v), params);


        // 15.lambda 条件构造器，支持 lambda 表达式，可以不必像普通条件构造器一样，以字符串形式指定列名，它可以直接以实体类的方法引用来指定列

        LambdaQueryWrapper<User> ding = new LambdaQueryWrapper<User>()
                .like(User::getName, "ding");

        //16. 链式 lambda 条件构造器
       /* List<User> userList1 = new LambdaQueryChainWrapper<User>((BaseMapper<User>) new UserServiceImpl())
                .likeLeft(User::getName, "黄")
                .and(c -> c.le(User::getAge, 40)).list();*/

        // 17.更新也类似上述查询的等值条件匹配
        // 当只需要更新一个值时，使用对象进行等值匹配有点繁琐。可以直接使用set

        LambdaUpdateWrapper<User> test = new LambdaUpdateWrapper<User>().eq(User::getId, 100).set(User::getName, "test");

        // 18.删除
        /*deleteById  根据主键 id 进行删除
         *deleteBatchIds  根据主键 id 进行批量删除
         * deleteByMap  根据 Map 进行删除（Map 中的 key 为列名，value 为值，根据列和值进行等值匹配）
         *delete(Wrapper<T> wrapper)  根据条件构造器Wrapper进行删除
         */


        // 19.分页查询
        Page<User> userPage = userService.page(new Page<>(1, 10), null);

    }

}
